// Package option
// @Author zhongxc
// @Date 2024/2/20 15:29:00
// @Desc
package main

import (
	"fmt"
)

type User struct {
	Name string
	Age  int
	Tags map[string]string
}

func (u *User) String() string {
	return fmt.Sprintf("{Name:%v, Age:%v, Tags: %v}", u.Name, u.Age, u.Tags)
}

func NewUser(opts ...UserOption) *User {
	user := new(User)
	for _, opt := range opts {
		opt(user)
	}
	return user
}

// UserOption 第一种方式，直接把Option定义为一个函数
type UserOption func(user *User)

func WithName(name string) UserOption {
	return func(user *User) {
		user.Name = name
	}
}

func WithAge(age int) UserOption {
	return func(user *User) {
		user.Age = age
	}
}

func WithTag(k, v string) UserOption {
	return func(user *User) {
		if user.Tags == nil {
			user.Tags = make(map[string]string)
		}
		user.Tags[k] = v
	}
}

// IUserOption 第二种方式，把Option定义一个接口，比第一种写法复杂了很多，但是接口里可以包含多个函数
type IUserOption interface {
	Apply(*User)
}

type UserName struct {
	Name string
}

// Apply UserName实现了接口IUserOption
func (un *UserName) Apply(user *User) {
	user.Name = un.Name
}

func NewUserName(name string) *UserName {
	return &UserName{
		Name: name,
	}
}

type UserAge func(*User)

// Apply UserAge实现了接口IUserOption
func (ua UserAge) Apply(user *User) {
	ua(user)
}

func NewUser2(opts ...IUserOption) *User {
	user := new(User)
	for _, opt := range opts {
		opt.Apply(user)
	}
	return user
}

func constructUser() {
	user1 := NewUser(
		WithName("小乔"),
		WithAge(20),
		WithTag("capital", "100W"),
	)
	fmt.Printf("%+v\n", *user1)

	ageOpt := func(u *User) {
		u.Age = 18
	}
	user2 := NewUser2(NewUserName("大乔"), UserAge(ageOpt))
	fmt.Printf("%+v\n", *user2)
}

// FilterOption 把查询条件参数，Option定义一个接口
type FilterOption interface {
	Judge(*User) bool
}

type NameEqual struct {
	Name string
}

func (ne *NameEqual) Judge(user *User) bool {
	if user.Name == ne.Name {
		return true
	} else {
		return false
	}
}

type AgeBetween struct {
	FromAge int
	ToAge   int
}

func (ab *AgeBetween) Judge(user *User) bool {
	if user.Age >= ab.FromAge && user.Age <= ab.ToAge {
		return true
	} else {
		return false
	}
}

func UserQuery(filters ...FilterOption) []*User {
	// 模拟从数据库里检索出了一批User
	var users []*User
	users = append(users, &User{Name: "小乔", Age: 19})
	if len(filters) == 0 {
		return users
	}
	filteredUsers := make([]*User, 0, len(users))
L:
	for _, user := range users {
		for _, opt := range filters {
			// 但凡有一个条件不满足，检查下一个User
			if !opt.Judge(user) {
				continue L
			}
		}
		filteredUsers = append(filteredUsers, user)
	}
	return filteredUsers
}

func getUser() {
	result := UserQuery()
	result = UserQuery(&NameEqual{Name: "小乔"})
	result = UserQuery(&AgeBetween{FromAge: 19, ToAge: 28})
	result = UserQuery(&NameEqual{Name: "小乔"}, &AgeBetween{FromAge: 19, ToAge: 28})

	fmt.Printf("%+v\n", result)
}

func main() {
	constructUser()
	getUser()
}
